package com.sinodata.bsm.cicp.collector.file;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.cicp.util.CollectorUtil;
import com.sinodata.bsm.cicp.util.CommandReader;
import com.sinodata.bsm.cicp.util.FileAttribute;
import com.sinodata.bsm.cicp.util.ProtocolParameterUtil;
import com.sinodata.bsm.common.constants.DataTypeConstants;
import com.sinodata.bsm.common.utils.FileUtil;
import com.sinodata.bsm.common.vo.ProtocolParameter;
import com.sinodata.bsm.common.vo.ResPropertyValue;

/**
 * 
 * <p>
 * Description: 日志文件内容监控(原日志文件过滤，替代原来的日志文件内容监控)
 *              目前适用于Linux、Unix机器文件内容监控 2012-11-22
 *              
 *              2012-12-20 间隔时间(Interval)改为 是否合并，默认为合并，界面传入“否”、“NO”、“0”、“不是” 均代表否
 *              
 *              
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-11-22 17:33:41      liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class LogFileCollector2 extends Collector {

    private static Logger logger = Logger.getLogger(LogFileCollector2.class);

    public LogFileCollector2() {

    }

    @Override
    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        String filePath = this.getParamMap().get("FilePath").trim();//文件路径
        String fileNameRegex = this.getParamMap().get("FilePattern").trim();//文件匹配正则表达式
        String errFlag = this.getParamMap().get("ErrorFlag").trim();//错误标识
        //是否合并判断开始
        boolean isMerge = true;
        String isMergeStr = this.getParamMap().get("Interval").trim();//是否合并
        if (isMergeStr != null) {
            if (isMergeStr.equals("否") || isMergeStr.equals("0") || isMergeStr.equals("NO") || isMergeStr.equals("不是")) {
                isMerge = false;
            }
        }
        //是否合并判断结束
        ProtocolParameter protocolParameter = ProtocolParameterUtil.getHostValue(ip);
        String filterDir = protocolParameter.getUrl();
        String fullFileName = getFullFileName(filePath, fileNameRegex);
        String tmpFileName = getTmpFileName(fullFileName, errFlag, ip);
        FileAttribute lastAttribute = (FileAttribute) FileUtil.readObjFromFile(tmpFileName);
        //TODO 时间有问题
        Long time = lastAttribute == null ? null : (Calendar.getInstance().getTimeInMillis() - lastAttribute.lastTime) / 1000 / 60;
        List<FileAttribute> modifiedFileList = CollectorUtil.getModifiedFiles(filePath, fileNameRegex, time, ip);
        if (modifiedFileList == null) {
            return null;
        }
        List<ResPropertyValue> result = null;
        if (lastAttribute != null) {
            result = readFile(filePath, modifiedFileList, filterDir, isMerge, lastAttribute, errFlag, ip);
        } else {//lastAttribute 为空 第一次采集，返回未产生新错误
            String[] propMetas = getPropMeta();
            ResPropertyValue propertyValueX = new ResPropertyValue();
            ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];
            result = new ArrayList<ResPropertyValue>();
            propValues[0] = ResPropertyValue.createPropValue(DataTypeConstants.BOOLEAN_VALUE_FALSE, propMetas[0]);
            propValues[1] = ResPropertyValue.createPropValue(modifiedFileList.get(0).name, propMetas[1]);
            propValues[2] = ResPropertyValue.createPropValue(" ", propMetas[2]);
            propValues[3] = ResPropertyValue.createPropValue("0", propMetas[3]);
            propertyValueX.setValues(propValues);
            result.add(propertyValueX);
        }

        // 记录文件位置
        if (lastAttribute == null || !lastAttribute.equals(modifiedFileList.get(0))) {
            try {
                FileAttribute fileAttribute = modifiedFileList.get(0);
                fileAttribute.lastTime = Calendar.getInstance().getTimeInMillis();
                FileUtil.forceWriteObjToFile(tmpFileName, fileAttribute, false);
            } catch (Exception e) {
                logger.error("failed to call " + this.getClass().getName() + ".collect()", e);
                throw new CollectorException(e);
            }
        }
        return result;
    }

    /**
     * @param modifiedFileList
     * @param filterDir
     * @param isMerge
     * @param size
     * @param errFlag
     * @param ip
     * @param propertyValueX
     * @param propValues
     * @param propMetas
     * @return
     */
    private List<ResPropertyValue> readFile(String filePath, List<FileAttribute> modifiedFileList, String filterDir, boolean isMerge, FileAttribute lastAttribute, String errFlag, String ip) {
        List<ResPropertyValue> result = new ArrayList<ResPropertyValue>();
        String[] propMetas = getPropMeta();
        ResPropertyValue propertyValueX = new ResPropertyValue();
        ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];

        if (filePath != null && !filePath.equals("")) {
            filePath = filePath.trim();
            if (!filePath.endsWith("/")) {
                filePath += "/";
            }
        }
        if (filterDir != null && !filterDir.equals("")) {
            filterDir = filterDir.trim();
            if (!filterDir.endsWith("/")) {
                filterDir += "/";
            }
        }
        String cmdHead;
        if (filterDir != null) {
            cmdHead = filterDir + "filter -p '" + errFlag + "' -f " + filePath;
        } else {
            cmdHead = "filter -p '" + errFlag + "' -f " + filePath;
        }
        BufferedReader reader = null;
        int count = 0;
        boolean update = false;
        String strLine = null;
        for (int i = modifiedFileList.size() - 1; i >= 0; i--) {
            FileAttribute fileAttribute = modifiedFileList.get(i);
            String cmd = cmdHead + fileAttribute.name + " -s ";
            if ((i == modifiedFileList.size() - 1) && lastAttribute.size < fileAttribute.size && (modifiedFileList.size() > 1 || lastAttribute.name.equals(fileAttribute.name))) {
                cmd += lastAttribute.size;
            } else {
                cmd += 0;
            }
            try {
                reader = CommandReader.getReader(ip, cmd, 0, 0);
                while ((strLine = reader.readLine()) != null) {
                    strLine = strLine.trim();
                    if (strLine.length() > 0) {
                        //2013-2-23 原机制为 相同内容进行合并， 修改为 只要检测到错误就和合并
                        if (isMerge) {//相同内容进行合并
                            if (!update) {//未匹配到认为是新记录
                                propertyValueX = new ResPropertyValue();
                                propValues = new ResPropertyValue.PropValue[propValues.length];
                                propValues[0] = ResPropertyValue.createPropValue(DataTypeConstants.BOOLEAN_VALUE_TRUE, propMetas[0]);
                                propValues[1] = ResPropertyValue.createPropValue(fileAttribute.name, propMetas[1]);
                                propValues[2] = ResPropertyValue.createPropValue(strLine, propMetas[2]);
                                propValues[3] = ResPropertyValue.createPropValue("1", propMetas[3]);
                                propertyValueX.setValues(propValues);
                                result.add(propertyValueX);
                                update = true;// 单独加一行 2013-2-23 原机制为 相同内容进行合并， 修改为 只要检测到错误就和合并
                            }
                            count++;
                        } else {
                            propertyValueX = new ResPropertyValue();
                            propValues = new ResPropertyValue.PropValue[propValues.length];
                            propValues[0] = ResPropertyValue.createPropValue(DataTypeConstants.BOOLEAN_VALUE_TRUE, propMetas[0]);
                            propValues[1] = ResPropertyValue.createPropValue(fileAttribute.name, propMetas[1]);
                            propValues[2] = ResPropertyValue.createPropValue(strLine, propMetas[2]);
                            propValues[3] = ResPropertyValue.createPropValue("1", propMetas[3]);
                            propertyValueX.setValues(propValues);
                            result.add(propertyValueX);
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (isMerge) {
            result.get(0).getValues()[3].value = count + "";
        }
        return result;
    }

    /**
     * 
     * 获取全文件文件名
     * 
     * @param path
     * @param fileName
     * @return
     */
    private String getFullFileName(String path, String fileName) {
        path = path.trim();
        if (path.endsWith("/")) {
            return path + fileName;
        } else {
            return path + "/" + fileName;
        }
    }

    /**
     * 获取临时文件的文件名
     * 
     * @param fileName
     * @param errFlag
     * @param ip
     * @return
     */
    private String getTmpFileName(String fileName, String errFlag, String ip) {
        String path = "tmp/";
        StringBuffer buffer = new StringBuffer();
        buffer.append(ip).append("_").append(fileName).append("_").append(errFlag);
        return path + FileUtil.validateFileName(buffer.toString());
    }

    /*
     * (non-Javadoc)
     * @see com.sinodata.bsm.cicp.collector.Collector#getParamMeta()
     * FilePath              文件路径
     * FilePattern           文件匹配正则表达式
     * ErrorFlag             错误标识
     * Interval              时间间隔  改为  是否合并
     */
    @Override
    public String[] getParamMeta() {
        return new String[] { "FilePath", "FilePattern", "ErrorFlag", "Interval" };
    }

    /*
     * (non-Javadoc)
     * @see com.sinodata.bsm.cicp.collector.Collector#getPropMeta()
     * $1  isNewMistake  是否产生新错误
     * $2  fileName      文件匹配正则表达式
     * $3  Content       错误内容
     * $4  timeout       间隔时间内错误出现次数
     */
    @Override
    public String[] getPropMeta() {
        return new String[] { "$1", "$2", "$3", "$4" };
    }

    public static void main(String[] args) {
        LogFileCollector2 a = new LogFileCollector2();
        try {
            List<ResPropertyValue> list = a.collect("172.168.2.8");
        } catch (CollectorException e) {
            e.printStackTrace();
        }
    }
}